#include <unistd.h>
#include <sys/types.h>       /* basic system data types */
#include <sys/socket.h>      /* basic socket definitions */
#include <netinet/in.h>      /* sockaddr_in{} and other Internet defns */
#include <arpa/inet.h>       /* inet(3) functions */
#include <netdb.h> 		  /*gethostbyname function */
#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h> 
#include <linux/types.h>
#include <sys/stat.h>
#include <time.h>
#include <sys/select.h>
#include <termios.h>

 #include "p_lib.h"
#include "pub.h"
 #include "socket_base.h"

#include "file_request.h"

#include  "common.h"


/*================================================================
FILE REQUEST PART
=================================================================*/
File_List SimFileTab[] = 
{
	{1,		tag_fcb, "/FCB.dat", 0},
	{2,		tag_fch, "/FCH.dat", 0xFF},
	{3,		tag_fcp, "/FCP.dat", 0},
	{4,		tag_fct, "/FCT.dat", 0},
	{5,		tag_atr, "/ATR.dat", 0},
	{0xFF, 	0xFF, 	 "/FCB.dat", 0},
};

int TCP_SimFileRequestCmd(int nfd, File_List *FN, unsigned char FileBlockNum)
{
	char * p_CmdHead = NULL;
	unsigned char TcpRecvBuf[128];
	unsigned char TcpSendBuf[256];
	memset(TcpRecvBuf, 0x00, sizeof(TcpRecvBuf));
	memset(TcpSendBuf, 0x00, sizeof(TcpSendBuf));
	
	TcpSendBuf[0] = TAG_SIMFILE_REQUEST;
	TcpSendBuf[1] = 2;
	TcpSendBuf[2] = FN->RequestFileTag;
	TcpSendBuf[3] = FileBlockNum;
	
	if(0 > TCP_SendMessage(nfd, TcpSendBuf, 4))
	{
		perror("Send FileRequest Cmd Failed:");
		return 1;
	}

	return 0;
}

/** 
 * Brief description:
	   used for cal file block which was get from server mod 256 
 * Detail description:
 * 
 * @param[in]
   const unsigned char * Buf
   int len
 * @param[out]	the result of cal
 * @retval	CS-code-hex
 * 
 * @par  Buf
 *			
 * @par  len
 *	   
 * @par  
 *	  
 */ 
unsigned char ADD_CS_Cal(const unsigned char *Buf, int len)
{
	int i;
	unsigned char Ret = 0;
	for (i = 0; i < len; i++)
	{
		Ret += (*(Buf + i));
	}

	return Ret;
}

#if 0
/** 
 * Brief description:
	   Write data to file 
 * Detail description:
 * 
 * @param[in]
   FILE * fp
   unsigned char *SrcBuf
   int length
   File_List *FN
 * 
 * @param[out]	the result of cal
 * @retval	file write status
 * 
 * @par  *fp
 *			
 * @par  *SrcBuf
 *	   
 * @par  length
 *	  
 * @par  *FN
 */ 
#endif

int SimFileDataVerify(unsigned char *BlockDat, int BlockSize)
{
	unsigned char CS_CAL = 0;
	CS_CAL = ADD_CS_Cal(BlockDat, BlockSize);
	if(CS_CAL !=* (BlockDat + BlockSize))
	{
		DBUG("CS erro:Recved CS=%02x, Cal_CS=%02x\n", *(BlockDat+BlockSize), CS_CAL);
		return -1;
	}
	else 
		return 0;
}

int SimFileRequestResultANL(unsigned char tag, unsigned char *Src, unsigned char *Dst, int *TotalBlock)
{
	TD_ComProtocl_RecvFrame_t * p_Src = (TD_ComProtocl_RecvFrame_t *)Src;
	FileRequestFrameBody_t FileBlock;
	int FrameSize = 0;
	int BlockSize = 0;
	if(TAG_RESULT_SIMFILE_REQUEST != p_Src->Cmd_TAG)
	{
		DBUG("unknown TAG :%02x\n", p_Src->Cmd_TAG);
		return -1;
	}
	FrameSize = (256 * p_Src->FrameSizeH + p_Src->FrameSizeL);
	BlockSize = FrameSize - 4;//head 3 bytes and tail 1byte
	
	FileBlock.tag = p_Src->Frame_Data[0];
	FileBlock.TotalBlock = p_Src->Frame_Data[1];
	FileBlock.BlockNum = p_Src->Frame_Data[2];
	if(tag != FileBlock.tag)
	{
		DBUG("Error:File mixed \n");
		return -2;
	}
	
	FileBlock.p_Data = 3 + p_Src->Frame_Data;
	if(SimFileDataVerify(FileBlock.p_Data, BlockSize))
	{
		return -3;
	}
		
	if(1 == *TotalBlock)
	{
		*TotalBlock = FileBlock.TotalBlock;
	}
	memcpy(Dst, FileBlock.p_Data, BlockSize);
	
	return BlockSize;
}

int TCP_SimFileRequest(int nfd, File_List *FN, AccessAuth_Result_t *AA_Result)
{
//	FILE *fp = NULL;
	int length = 0;
	unsigned int file_size = 0;
	unsigned char File_Buf[4096];
	unsigned char TcpRecvBuf[1024];
	char FileName[128];
	char sIMSI[32];
	int sta = -1;
	int i = 0;
	int TotalBlock = 1;

	memset(File_Buf, 0x00, sizeof(File_Buf));
	memset(FileName, 0x00, sizeof(FileName));
    memset(sIMSI, 0, sizeof(sIMSI));


    DBUG( "request file %s start\n", FN->LocalFileName);

    do{
        memset(TcpRecvBuf, 0x00, sizeof(TcpRecvBuf));
        if(TCP_SimFileRequestCmd(nfd, FN, i))
		{
//			fclose(fp);
            DBUG("error ************************************************");
			return -1;
		}

		length = TCP_RecvMessage(nfd, TcpRecvBuf, 0, MSG_WAITALL, 30);
		if(length < 0)
		{
			DBUG( "block_%d of %s RQ fail ERR.%d\n", i, FN->LocalFileName, length);
			switch(length)
			{
				case ERR_TIME_OUT:
				case ERR_RECV:
				default:
//					fclose(fp);
					return -2;
					break;
			}
			continue;
		}
		//DBUG("%s, length=%d", FN->LocalFileName, length);
		hex2str(TcpRecvBuf, length);
		length = SimFileRequestResultANL(FN->RequestFileTag, TcpRecvBuf, File_Buf+file_size, &TotalBlock);
		if(length < 0)
		{
			length = 0;
			i--;
		}
		file_size += length;
		i++;
	}while(i < TotalBlock);
	
	DBUG( "file %s Recv OK\n", FN->LocalFileName);
	//if(fwrite(File_Buf, sizeof(char), file_size, fp) < file_size)  
	DBUG("FN->LocalFileName = %s, %d",FN->LocalFileName, file_size);
    switch(FN->Fn)
    {
        case 1:
            memset(Data.File_FCB, 0, sizeof(Data.File_FCB));
            memcpy( Data.File_FCB,File_Buf,file_size);
            Data.FCH_Size = file_size;
            break;
        case 2:
            memset(Data.File_FCH, 0, sizeof(Data.File_FCH));
            memcpy( Data.File_FCH,File_Buf,file_size);
            Data.FCH_Size = file_size;
            break;
        case 3:
            memset(Data.File_FCP, 0, sizeof(Data.File_FCP));
            memcpy( Data.File_FCP,File_Buf,file_size);
            Data.FCP_Size = file_size;
            break;
        case 4:
            memset(Data.File_FCT, 0, sizeof(Data.File_FCT));
            memcpy( Data.File_FCT,File_Buf,file_size);
            Data.FCT_Size = file_size;
            break;
        case 5:
            memset(Data.DEFAULT_ATR, 0, sizeof(Data.DEFAULT_ATR));
            memcpy( Data.DEFAULT_ATR,File_Buf,file_size);
            Data.ATR_Len = file_size;
            break;
        default:
            break;
    }

	return 0;
}
 
int SimFileRequest_main(int socket_fd, AccessAuth_Result_t *AA_Result)
{
	int i = 0 ;
	int status = 0;
	

	for(i = 0; i < 5; i++)
	{
		status = TCP_SimFileRequest(socket_fd, &(SimFileTab[i]), AA_Result);
		if(status < 0)
		{
			DBUG( "File %s request fail because of Socket recv erro\n", SimFileTab[i].LocalFileName);
			return SIM_FILE_CHECK_ERR;
		}
		else if(status > 0)
		{
			DBUG( "File read or write %s file error, retry\n", SimFileTab[i].LocalFileName);
			i--;
		}
		else
			DBUG("File %s get OK!\n", SimFileTab[i].LocalFileName);
	}

	return 0;
}
